---
layout: layouts/page.njk
title: Accordion
description: A vertically stacked set of interactive headings that each reveal a section of content.
toc:
  - label: Usage
    id: usage
---

{% from "macros/code_preview.njk" import code_preview %}

<div class="alert mb-6">
  {% lucide "circle-alert" %}
  <h2>There is no dedicated Accordion component in Basecoat.</h2>
</div>

{% set code %}<section class="accordion">
  <details class="group border-b last:border-b-0 ">
    <summary class="w-full focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] transition-all outline-none rounded-md">
      <h2 class="flex flex-1 items-start justify-between gap-4 py-4 text-left text-sm font-medium hover:underline ">
        Is it accessible?
        {% lucide "chevron-down", { "class": "text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200 group-open:rotate-180" } %}
      </h2>
    </summary>
    <section class="pb-4">
      <p class="text-sm">Yes. It adheres to the WAI-ARIA design pattern.</p>
    </section>
  </details>
  <details class="group border-b last:border-b-0">
    <summary class="w-full focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] transition-all outline-none rounded-md">
      <h2 class="flex flex-1 items-start justify-between gap-4 py-4 text-left text-sm font-medium hover:underline ">
        Is it styled?
        {% lucide "chevron-down", { "class": "text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200 group-open:rotate-180" } %}
      </h2>
    </summary>
    <section class="pb-4">
      <p class="text-sm">Yes. It comes with default styles that matches the other components' aesthetic.</p>
    </section>
  </details>
  <details class="group border-b last:border-b-0">
    <summary class="w-full focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] transition-all outline-none rounded-md">
      <h2 class="flex flex-1 items-start justify-between gap-4 py-4 text-left text-sm font-medium hover:underline ">
        Is it animated?
        {% lucide "chevron-down", { "class": "text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200 group-open:rotate-180" } %}
      </h2>
    </summary>
    <section>
      <p class="text-sm whitespace-pre-wrap">Yes. It's animated by default, but you can disable it if you prefer.</p>
    </section>
  </details>
</section>
<script>
  (() => {
    const accordions = document.querySelectorAll('.accordion');
    accordions.forEach(accordion => {
      accordion.addEventListener('click', (event) => {
        const summary = event.target.closest('summary');
        if (!summary) return;
        const details = summary.closest('details');
        if (!details) return;
        accordion.querySelectorAll('details').forEach(detailsEl => {
          if (detailsEl !== details) {
            detailsEl.removeAttribute('open');
          }
        });
      });
    });
  })();
</script>
{% endset %}
{{ code_preview("accordion", code | prettyHtml, "w-full max-w-md") }}

<h2 id="usage"><a href="#usage">Usage</a></h2>

<p class="prose">Basecoat already animates <code>&lt;details&gt;</code> elements by default. The example add some Tailwind CSS utility classes for style and a bit of vanilla JavaScript to handle the open/close state.</p>